package com.quectel.business.pay.handler;

import cn.hutool.core.bean.BeanUtil;
import com.quectel.business.common.propertybill.PropertyBillBusiness;
import com.quectel.business.pay.handler.model.CreateBusinessResp;
import com.quectel.business.pay.vo.CreateOrderRequest;
import com.quectel.constant.core.propertybill.PropertyBillConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.core.module.propertybill.dto.PropertyBillDto;
import com.quectel.core.module.propertybill.dto.PropertyChargeableListDueDateDto;
import com.quectel.core.module.propertybill.service.PropertyBillService;
import com.quectel.core.module.propertybill.service.PropertyChargeableListDueDateService;
import com.quectel.core.module.propertybill.vo.PropertyBillAmountVo;
import com.quectel.pay.module.order.dto.PayOrderDto;
import com.quectel.pay.module.order.dto.PayOrderRefundDto;
import com.quectel.pay.module.order.service.PayOrderService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Response;
import com.quectel.util.redis.RedisUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.locks.Lock;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/4/20 10:29
 * @description new java file header...
 */
@Slf4j
@Component
public class PropertyBillPayHandler implements BasePayHandler {
    @DubboReference
    private PropertyBillService propertyBillService;
    @DubboReference
    private PropertyChargeableListDueDateService propertyChargeableListDueDateService;
    @Autowired
    private PropertyBillBusiness propertyBillBusiness;
    @DubboReference
    private PayOrderService payOrderService;
    @DubboReference
    private HouseholdService householdService;

    /**
     * 订单有效支付时间
     */
    private static final long TTL = 1L * 60 * 1000;
    /**
     * 下一次安全时间间隔
     */
    private static final long SECURITY_TIME = TTL + 1L * 60 * 1000;

    @Data
    private static class PropertyBillBusinessParam {
        private Long propertyBillId;
    }

    @Override
    public Response<CreateBusinessResp> createBusinessOrder(CreateOrderRequest req) {
        log.info("createBusinessOrder:{}", JacksonUtils.toJsonString(req));

        PropertyBillBusinessParam param = BeanUtil.toBean(req.getOtherBusinessParams(), PropertyBillBusinessParam.class);
        Long propertyBillId = param.getPropertyBillId();

        Lock spinLock = RedisUtils.getSpinLock(PropertyBillConstants.BILL_OPERATE_LOCK_FUNC.apply(propertyBillId));
        spinLock.lock();


        try {
            Date nowDate = new Date();
            PropertyBillDto propertyBillDto = propertyBillService.selectById(propertyBillId);
            if (PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue().equals(propertyBillDto.getPayStatus())

            ) {
                return Response.error("订单被支付，无需重复支付");
            }

            if (PropertyBillConstants.PayStatus.INIT.getStatusValue().equals(propertyBillDto.getPayStatus())) {
                if (propertyBillDto.getLatestCreateOrderTime() != null) {

                    if (System.currentTimeMillis() - propertyBillDto.getLatestCreateOrderTime().getTime() < SECURITY_TIME) {
                        return Response.error("订单正在被支付，请稍后再试");
                    }
                }
            }
            PropertyChargeableListDueDateDto propertyChargeableListDueDateDto = propertyChargeableListDueDateService.selectByRoomInfoAndListId(
                    propertyBillDto.getTenantId(),
                    propertyBillDto.getVillageId(),
                    propertyBillDto.getRoomId(),
                    propertyBillDto.getChargeableListId()
            );
            if (propertyChargeableListDueDateDto == null || propertyChargeableListDueDateDto.getDueDate() == null) {
                return Response.error("无法获取该费用上一次的截至日期，请联系管理员");
            }


            //查询订单详情
            PropertyBillAmountVo propertyBillAmountVo = null;
            if (propertyBillDto.getPropertyBillAmount() == null) {
                propertyBillAmountVo = propertyBillBusiness.generatePropertyBill(
                        propertyBillDto.getChargeableListId(),
                        propertyBillDto.getRoomId(),
                        propertyBillDto.getStartDate(),
                        Boolean.TRUE);

            } else {
                propertyBillAmountVo = propertyBillDto.getPropertyBillAmount();
            }

            PropertyBillDto newPropertyBill = propertyBillBusiness.genBillByPropertyBillAmountVo(propertyBillAmountVo);
            //查询支付人信息
            HouseholdDto householdDto = householdService.selectByVillageIdAndMobile(newPropertyBill.getVillageId(), req.getMobile());
            if (householdDto != null) {
                propertyBillDto.setHouseholdId(householdDto != null ? householdDto.getId() : null);
            }

            //更新账单信息
            propertyBillBusiness.updateOriginBill(propertyBillDto, newPropertyBill);
            propertyBillDto.setPayStatus(PropertyBillConstants.PayStatus.INIT.getStatusValue());
            propertyBillDto.setPayAmount(propertyBillAmountVo.getTotalAmount());
            propertyBillDto.setPropertyBillAmount(propertyBillAmountVo);
            propertyBillDto.setLatestCreateOrderTime(nowDate);
            propertyBillDto.setUpdateTime(nowDate);
            propertyBillService.saveOrUpdateWithAmountVO(propertyBillDto);

            CreateBusinessResp createBusinessResp = new CreateBusinessResp();
            createBusinessResp.setTenantId(propertyBillDto.getTenantId());
            createBusinessResp.setVillageId(propertyBillDto.getVillageId());
            createBusinessResp.setBusinessId(propertyBillDto.getId());
            createBusinessResp.setProductName(propertyBillDto.getPeriodName());
            createBusinessResp.setOriginalPrice(propertyBillDto.getItemAmount());
            createBusinessResp.setSpecialPrice(propertyBillDto.getTotalAmount());
            //TODO 测试添加 上线需要删除
            createBusinessResp.setSpecialPrice(BigDecimal.valueOf(0.01));
            createBusinessResp.setTtl(TTL);
            return Response.<CreateBusinessResp>ok().wrap(createBusinessResp);
        } catch (Exception e) {
            log.error("PropertyBillPayHandler createBusinessOrder error", e);
        } finally {
            spinLock.unlock();
        }

        return Response.error("业务订单创建失败");
    }

    @Override
    public Response<Object> createOrderSuccessNotify(PayOrderDto notifyOrder) {
        log.info("createOrderSuccessNotify:{}", JacksonUtils.toJsonString(notifyOrder));
        //创建订单成功保存通用订单详情
        //1.查询订单
        PropertyBillDto propertyBillDto = propertyBillService.selectById(notifyOrder.getBusinessId());
        //2.查询和保存通用订单信息
        PayOrderDto payOrderDto = payOrderService.selectByOutTradeNo(notifyOrder.getOutTradeNo());
        if (payOrderDto != null) {
            propertyBillDto.setOrderId(payOrderDto.getId());
            propertyBillDto.setOrderNo(payOrderDto.getTradeNo());
            propertyBillService.updateById(propertyBillDto);
        }
        return Response.ok();
    }

    @Override
    public Response<Object> createOrderFailedNotify(CreateOrderRequest req) {
        log.info("createOrderFailedNotify:{}", JacksonUtils.toJsonString(req));
        return Response.ok();
    }

    @Override
    public Response<Object> cancelOrder(PayOrderDto cancelOrder) {
        log.info("cancelOrder:{}", JacksonUtils.toJsonString(cancelOrder));

        PropertyBillDto propertyBillDto = propertyBillService.selectById(cancelOrder.getBusinessId());

        Lock spinLock = RedisUtils.getSpinLock(PropertyBillConstants.BILL_OPERATE_LOCK_FUNC.apply(cancelOrder.getBusinessId()));
        spinLock.lock();

        try {
            //待支付订单可以取消
            if (PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue().equals(propertyBillDto.getPayStatus())) {
                return Response.error("订单被支付，不能取消");
            }

            //回滚订单
            PropertyBillAmountVo propertyBillAmountVo = propertyBillBusiness.generatePropertyBill(
                    propertyBillDto.getChargeableListId(),
                    propertyBillDto.getRoomId(),
                    propertyBillDto.getStartDate(),
                    Boolean.FALSE);

            PropertyBillDto newPropertyBill = propertyBillBusiness.genBillByPropertyBillAmountVo(propertyBillAmountVo);
            //更新账单信息
            propertyBillBusiness.updateOriginBill(propertyBillDto, newPropertyBill);
            propertyBillDto.setPayStatus(PropertyBillConstants.PayStatus.CANCEL.getStatusValue());
            propertyBillDto.setPayAmount(null);
            propertyBillDto.setPropertyBillAmount(propertyBillAmountVo);
            propertyBillDto.setUpdateTime(new Date());
            //赠品相关
            propertyBillDto.setGiftFlag(SystemConstants.NO);
            if(propertyBillDto.getPropertyBillAmount() !=null && propertyBillDto.getPropertyBillAmount().getGiftList()!=null){
                propertyBillDto.setGiftNum(propertyBillDto.getPropertyBillAmount().getGiftList().size());
                propertyBillDto.setGiftFlag(SystemConstants.NO);
            }else{
                propertyBillDto.setGiftNum(0);
                propertyBillDto.setGiftFlag(SystemConstants.YES);
            }

            propertyBillService.saveOrUpdateWithAmountVO(propertyBillDto);
            return Response.ok();
        } catch (Exception e) {
            log.error("PropertyBillPayHandler cancelOrder error", e);
        } finally {
            spinLock.unlock();
        }


        return Response.error("业务订单取消失败");
    }

    @Override
    public Response<Object> paySuccessNotify(PayOrderDto order) {
        log.info("paySuccessNotify:{}", JacksonUtils.toJsonString(order));

        PropertyBillDto propertyBillDto = propertyBillService.selectById(order.getBusinessId());
        //更新状态和时间
        propertyBillDto.setPayStatus(PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue());
        propertyBillDto.setUpdateTime(new Date());
        propertyBillDto.setPayTime(order.getPayTime());

        //查询和保存通用订单信息
        PayOrderDto payOrderDto = payOrderService.selectByOutTradeNo(order.getOutTradeNo());
        if (payOrderDto != null) {
            propertyBillDto.setOrderId(payOrderDto.getId());
            propertyBillDto.setOrderNo(payOrderDto.getTradeNo());
        }
        //更新账单
        propertyBillService.billPaySuccessUpdateDueDate(propertyBillDto);
        return Response.error("支付失败");
    }

    @Override
    public Response<Object> refundPreCheck(PayOrderDto payOrderDto, BigDecimal refundAmount) {
        log.info("refundPreCheck:{},{}", JacksonUtils.toJsonString(payOrderDto), JacksonUtils.toJsonString(refundAmount));
        return Response.ok();
    }

    @Override
    public Response<Object> refundSuccessNotify(PayOrderRefundDto refundOrder) {
        return null;
    }
}
